/**
 * MCU 系统时钟适配 API
 * 张勇 41204@qq.com
 */

#include <stdlib.h>
#include <sys/time.h>
#include <FreeRTOS.h>
#include <task.h>

#include "xtmrctr.h"
#include "sleep.h"
#include "mcu.h"

extern XTmrCtr xTickTimerInstance;

static uint64_t mcu_msec_count = 0;
static uint64_t mcu_sec_count = 0;

/* This is a default implementation of what is otherwise an application defined
callback function used to clear whichever timer interrupt is used to generate
the tick interrupt.  It is provided as an application callback because the
kernel will run on lots of different MicroBlaze and FPGA configurations - not
all of which will have the same timer peripherals defined or available.
vApplicationSetupTimerInterrupt() is declared as a weak symbol, allowing the
application writer to provide their own implementation, if this default
implementation is not suitable. */
void vApplicationClearTimerInterrupt()
{
unsigned long ulCSR;

	/* Clear the timer interrupt */
	ulCSR = XTmrCtr_GetControlStatusReg( XPAR_RTOS_TIMER_BASEADDR, 0 );
	XTmrCtr_SetControlStatusReg( XPAR_RTOS_TIMER_BASEADDR, 0, ulCSR );
	mcu_msec_count += portTICK_PERIOD_MS;
	if(mcu_msec_count >= 1000){
		mcu_msec_count -= 1000;
		mcu_sec_count ++;
	}
}

uint64_t mcu_clock_us_now() {
	uint32_t tCur = XPAR_RTOS_TIMER_CLOCK_FREQ_HZ / configTICK_RATE_HZ - XTmrCtr_GetValue(&xTickTimerInstance, 0);
	return tCur * 1000000 / XPAR_RTOS_TIMER_CLOCK_FREQ_HZ;
}

uint64_t mcu_clock_ms_now() {
	return mcu_msec_count;
}

void mcu_clock_us_delay(uint32_t x) {
	if(!x) return;
	//传入的参数是时间(单位:us)，乘以10转换为timer的ticks(单位:10ns)
	uint64_t x_temp = x * 1000;
	//记录进入函数时间点
	uint64_t old = XTmrCtr_GetValue(&xTickTimerInstance, 1);
	//记录当前时间点
	uint64_t current = XTmrCtr_GetValue(&xTickTimerInstance, 1);
	//计算过去了多少时间,用比较来防止计时器刚好reload的情况
	uint64_t left = (current > old) ? current - old : current + UINT32_MAX - old;
	//如果过去的时间不到delay的大小，持续阻塞
	while(left < x_temp){
		//记录当前时间点
		current = XTmrCtr_GetValue(&xTickTimerInstance, 1);
		//计算过去了多少时间
		left = (current > old) ? current - old : current + UINT32_MAX - old;
	}
}

void mcu_clock_ms_delay(uint32_t x) {
#if USE_FREERTOS
//	vTaskDelay((x) / portTICK_PERIOD_MS);
	mcu_clock_us_delay(x*1000);
#else
	usleep(x * 1000);
#endif
}

static uint64_t _gtbase = 0;     // osSetTime() 时 XTime_GetTime() 获取的全局时钟计数值
static uint32_t _secbase = 0; // osSetTime() 时设置的从 1970-01-01 00:00:00 开始计算的秒数

uint32_t mcu_clock_get_rtcsec() {
	// 计算从上次 osSetTime() 到现在过去了多少个秒
	uint32_t gt = mcu_sec_count;
	gt = (gt > _gtbase) ? (gt - _gtbase) : (UINT64_MAX - _gtbase + gt);
	// 转换为从 1970-01-01 00:00:00 开始计算的秒数
	return _secbase + gt;
}

/// @brief 设置当前时间(自1970-1-1 00:00:00至当前的秒数)
std_err_t mcu_clock_set_rtcsec(uint32_t sec) {
//	XTime_GetTime(&_gtbase);
	_secbase = sec;
	return STD_ERR_OK;
}

// 实现 ANSI C 函数 _gettimeofday()
int gettimeofday(struct timeval *tv, void *tzvp) {
    tv->tv_sec = mcu_clock_get_rtcsec();
    tv->tv_usec = mcu_clock_us_now() % 1000000;  // get remaining microseconds
    return 0;  // return non-zero for error
}

std_err_t mcu_clock_init() {

	//调用freertos系统的时钟初始化函数，此函数需要进行额外处理->已经初始化之后再调用直接返回OK
	vApplicationSetupTimerInterrupt();

	return STD_ERR_OK;
}

std_err_t times(){
	usleep(10);
	usleep(10);
	usleep(10);
}
